package com.newtouch.bxzs.account.controller;

import com.newtouch.bxzs.account.model.ClaimSet;
import com.newtouch.bxzs.account.model.UserLoginBO;
import com.newtouch.bxzs.account.model.UserLoginVO;
import com.newtouch.bxzs.account.model.UserRegisterVO;
import com.newtouch.bxzs.account.service.JwtGenerator;
import com.newtouch.bxzs.account.service.SystemParameterClient;
import com.newtouch.bxzs.account.service.UserService;
import com.newtouch.bxzs.common.base.BaseErrorEnum;
import com.newtouch.bxzs.common.base.BaseException;
import com.newtouch.bxzs.common.base.model.User;
import com.newtouch.bxzs.common.base.model.bo.UserDetailBO;
import com.newtouch.bxzs.common.base.model.bo.UserMenuListBO;
import com.newtouch.bxzs.common.base.response.BaseResponse;
import com.newtouch.bxzs.common.base.response.RespGenerator;
import com.newtouch.bxzs.common.base.util.RedisUtils;
import com.nimbusds.jose.JOSEException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录Controller类
 *
 * <p>
 * <b>History:</b>
 * <table border="1">
 * <tr>
 * <th>Date</th>
 * <th>Operator</th>
 * <th>Memo</th>
 * </tr>
 * <tr>
 * <td>2021年3月4日</td>
 * <td>Amour</td>
 * <td>Create</td>
 * </tr>
 * </table>
 *
 * @author Amour
 * @version 1.0.0
 * @since 1.0.0
 */
@Api(tags = "登录Controller")
@RestController
@RequestMapping("/public")
@SuppressWarnings("unchecked")
public class LoginController {

    @Autowired
    private JwtGenerator jwt;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UserService userService;

    @Autowired
    SystemParameterClient systemParameterClient;


    /**
     * 获取缓存中的登录失败次数时需要的编码
     */
    private static final String LOGIN_DEFAULT_CODE = "LOGIN_DEFULT_NUMBER";
    /**
     * 获取缓存中的账号锁定时间时需要的编码
     */
    private static final String LOCK_USER_CODE = "LOCK_USER_TIME";
    /**
     * 最大登录失败次数
     */
    private Integer loginNum;
    /**
     * 账号锁定时间
     */
    private Integer lockTime;

    private Map<String, String> verCodeMap = new HashMap<String, String>();

    @GetMapping("/jwk.json")
    public Map<String, Object> index() throws ParseException, JOSEException {
        return jwt.getJWKSetSimple().toJSONObject();
    }

    /**
     * 初始化缓存
     */
    private void initRedis() {
        String param = redisUtils.get(LOGIN_DEFAULT_CODE);
        String paramTime = redisUtils.get(LOCK_USER_CODE);
        if (StringUtils.isEmpty(param) || StringUtils.isEmpty(paramTime)) {
            systemParameterClient.initSystemParameter();
            this.initRedis();
        }
        this.loginNum = Integer.parseInt(param);
        this.lockTime = Integer.parseInt(paramTime);
    }

    @ApiOperation("本地认证登录")
    @GetMapping("/login")
    public BaseResponse<UserLoginBO> login(@RequestParam("username") String username,
                                           @RequestParam("password") String password, @RequestParam("userFlag") Integer userFlag)
            throws JOSEException {
        User user = userService.login4Pc(username, password, userFlag, this.checkLock(username), lockTime);
        return RespGenerator.returnOK(this.initUser(user, userFlag));
    }

    @ApiOperation("统一认证登录")
    @PostMapping("/loginByUnifiedAuth")
    public BaseResponse<UserLoginBO> loginByUnifiedAuth(@RequestBody UserLoginVO userLoginVO) throws JOSEException {
        User user = userService.loginByUnifiedAuth(userLoginVO, this.checkLock((userLoginVO.getUsername())), lockTime);
        return RespGenerator.returnOK(this.initUser(user, userLoginVO.getUserFlag()));
    }

    @ApiOperation("手势密码登录")
    @PostMapping("/loginByHandPass")
    public BaseResponse<UserLoginBO> loginByHandPass(@RequestBody UserLoginVO userLoginVO) throws JOSEException {
        if (userLoginVO.getUserFlag() != 1) {
            throw new BaseException("仅支持APP端进行手势密码登录!");
        }
        // 验证手势密码
        User user = userService.login4Pc(userLoginVO, this.checkLock((userLoginVO.getUsername())), lockTime);
        return RespGenerator.returnOK(this.initUser(user, userLoginVO.getUserFlag()));
    }

    @ApiOperation("注册登录")
    @PostMapping("/register")
    public BaseResponse<UserDetailBO> register(@RequestBody UserRegisterVO userRegisterVO) {
        return RespGenerator.returnOK(userService.register(userRegisterVO));
    }

    @ApiOperation("退出登录")
    @GetMapping("/logout")
    @SneakyThrows
    public BaseResponse<Boolean> logOut(@RequestParam("token") String token) {
        return RespGenerator.returnOK(redisUtils.set(token, token, 12, TimeUnit.HOURS));
    }

    @ApiOperation("忘记密码时,检验手机号是否存在")
    @GetMapping("/checkPhone")
    public BaseResponse<String> checkPhone(@RequestParam("userPhone") String userPhone) {
        return RespGenerator.returnOK(userService.checkUserPhone(userPhone));
    }

    @ApiOperation("修改登录密码")
    @GetMapping("/updateLoginPassword")
    public BaseResponse<Integer> updateLoginPassword(@RequestParam("userPhone") String userPhone, @RequestParam("password") String password, @RequestParam("confirmPassword") String confirmPassword) {
        return RespGenerator.returnOK(userService.updateLoginPassword(userPhone, password, confirmPassword));
    }

    @ApiOperation("注册时,校验证件类型,证件号")
    @GetMapping("/checkCertificate")
    public BaseResponse<Integer> checkCertificate(@RequestParam("certificateType") String certificateType, @RequestParam("certificateNumber") String certificateNumber) {
        return RespGenerator.returnOK(userService.checkCertificate(certificateType,certificateNumber));
    }

    private Integer checkLock(String username) {
        if (loginNum == null || lockTime == null) {
            this.initRedis();
        }
        // 读取缓存判断是否被锁定
        String loginDefult = redisUtils.get(username);
        Integer loginDefultNumber = 0;
        if (!StringUtils.isEmpty(loginDefult)) {
            loginDefultNumber = Integer.parseInt(loginDefult);
        }
        if (loginNum != null && loginDefultNumber >= loginNum) {
            throw new BaseException(BaseErrorEnum.USER_NAME_LOCK);
        }
        return loginDefultNumber;
    }

    private UserLoginBO initUser(User user, Integer userFlag) throws JOSEException {
        List<UserMenuListBO> menuList = userService.getMenuList(user.getUserId(), String.valueOf(userFlag));
        final ClaimSet.ClaimSetBuilder builder = ClaimSet.builder().issuer("http://www.newtouch.com").keepMinutes(60)
                .userId(user.getUserId()).userJobNumber(user.getUserJobNumber()).userName(user.getUserName())
                .userLoginAccountNumber(user.getUserLoginAccountNumber())
                .userCertificateType(user.getUserCertificateType())
                .userCertificateNumber(user.getUserCertificateNumber())
                .userOrganizationCode(user.getUserOrganizationCode())
                .userOrganizationName(user.getUserOrganizationName()).userPhone(user.getUserPhone());
        // 用户信息
        UserDetailBO.UserDetailBOBuilder bulider = UserDetailBO.builder().userId(user.getUserId())
                .userJobNumber(user.getUserJobNumber()).userName(user.getUserName())
                .userLoginAccountNumber(user.getUserLoginAccountNumber())
                .userCertificateType(user.getUserCertificateType())
                .userCertificateNumber(user.getUserCertificateNumber())
                .userOrganizationCode(user.getUserOrganizationCode())
                .handPass(user.getUserLoginHandPass())
                .handPassEnable(user.getEnableHandPass())
                .userOrganizationName(user.getUserOrganizationName()).userPhone(user.getUserPhone());

        UserLoginBO result = new UserLoginBO();
        result.setToken(jwt.generateJwtToken(builder.build()));
        result.setMenuList(menuList);
        result.setUserDetail(bulider.build());
        return result;
    }

}
